package org.xiaog.fastdao.util;

import org.xiaog.fastdao.ResultMapping;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

/**
 * @author xiaog
 */
public class QueryUtil {

    private QueryUtil(){}

    public static Collection<Map<String,Object>> queryMapCollection(String sql, Object[] params) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        Collection<Map<String,Object>> list = new ArrayList<>();
        try {
            connection = DataSourceUtil.getConnection();
            pst = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pst.setObject(i+1,params[i]);
            }
            rs = pst.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnSize = rsmd.getColumnCount();
            while (rs.next()) {
                Map<String,Object> map = new HashMap<>(columnSize);
                for (int i = 0; i < columnSize; i++) {
                    String label = rsmd.getColumnLabel(i+1);
                    map.put(label,rs.getObject(label));
                }
                list.add(map);
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            DataSourceUtil.closeResource(connection,pst,rs);
        }
        return list;
    }

    public static  <E> Collection<E> querySingleCollection(String sql,Class<E> eClass, Object[] params) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        Collection<E> list = new ArrayList<>();
        try {
            connection = DataSourceUtil.getConnection();
            pst = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pst.setObject(i+1,params[i]);
            }
            rs = pst.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            String cn = rsmd.getColumnLabel(1);
            while (rs.next()) {
                E e = rs.getObject(cn,eClass);
                list.add(e);
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            DataSourceUtil.closeResource(connection,pst,rs);
        }
        return list;
    }

    public static  <E> Collection<E> queryBeanCollection(String sql,Class<E> eClass, Object[] params) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        List<E> list = new ArrayList<>();
        try {
            connection = DataSourceUtil.getConnection();
            pst = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pst.setObject(i+1,params[i]);
            }
            rs = pst.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnSize = rsmd.getColumnCount();
            String[] colNames = new String[columnSize];
            for (int i = 0; i < columnSize; i++) {
                colNames[i] = rsmd.getColumnLabel(i+1);
            }
            ResultMapping<E> mapping = ResultMapping.getInstance(eClass);
            while (rs.next()) {
                E e = eClass.newInstance();
                Class<E> clazz = (Class<E>) e.getClass();
                for (int i = 0; i < columnSize; i++) {
                    String label = rsmd.getColumnLabel(i+1);
                    String fn = mapping.getField(label);
                    if (fn != null) {
                        Field field = clazz.getDeclaredField(fn);
                        field.setAccessible(true);
                        Class<?> type = field.getType();
                        Object val = rs.getObject(label,type);
                        field.set(e,val);
                    }
                }
                list.add(e);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DataSourceUtil.closeResource(connection,pst,rs);
        }
        return list;
    }

    public static Map<String,Object> queryMap(String sql,boolean needException, Object[] params) {
        Collection<Map<String,Object>> list = queryMapCollection(sql,params);
        if (list.size() == 0){
            return null;
        }else if(list.size() > 1 && needException) {
            throw new RuntimeException("expected records is one, but greater than one");
        }else {
            return list.iterator().next();
        }
    }

    public static  <E> E queryBean(String sql,Class<E> eClass,boolean needException, Object[] params) {
        Collection<E> list = queryBeanCollection(sql,eClass,params);
        if (list.size() == 0) {
            return null;
        }else if (list.size() > 1 && needException) {
            throw new RuntimeException("expected records is one, but greater than one");
        }else {
            return list.iterator().next();
        }
    }

    public static  <E> E querySingle(String sql,Class<E> eClass,boolean needException, Object[] params) {
        Collection<E> list = querySingleCollection(sql,eClass,params);
        if (list.size() == 0) {
            return null;
        }else if (list.size() > 1 && needException) {
            throw new RuntimeException("expected records is one, but greater than one");
        }else {
            return list.iterator().next();
        }
    }
}
